package system.impl;

import lombok.Data;
import pojo.Evaluate;
import pojo.Movie;
import pojo.User;
import system.MovieSystem;
import tool.LogCat;
import tool.ReaderUtil;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Data
public class MovieSystemImpl implements MovieSystem,Serializable  {

    // 序列化对象到文件的方法
    public void serializeToFile(String fileName) {
        try (FileOutputStream fileOut = new FileOutputStream(fileName);
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            out.writeObject(this); // 序列化当前对象（MovieSystemImpl 实例）
            System.out.println("Serialized data is saved in " + fileName);
        } catch (IOException i) {
            i.printStackTrace();
        }
    }

    // 从文件读取对象并返回，读取失败返回 null
    public static MovieSystemImpl deserializeFromFile(String fileName) {
        MovieSystemImpl movieSystem = null;
        try (FileInputStream fileIn = new FileInputStream(fileName);
             ObjectInputStream in = new ObjectInputStream(fileIn)) {
            movieSystem = (MovieSystemImpl) in.readObject(); // 反序列化对象
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return movieSystem;
    }
    //省略了其他代码,怎么做

    //电影路径
    public static final String MOVIE_PATH = "moviedata/movie.txt";
    //用户路径
    public static final String USER_PATH = "moviedata/users.txt";
    //评价路径
    public static final String EVALUATE_PATH = "moviedata/rate.txt";

    //电影列表
    List<Movie> movieList = List.of();
    //评价列表
    List<Evaluate> evaluateList = List.of();
    //用户列表
    List<User> userList = List.of();

    //全参构造
    public MovieSystemImpl(List<Movie> movieList, List<Evaluate> evaluateList, List<User> userList) {
        this.movieList = movieList;
        this.evaluateList = evaluateList;
        this.userList = userList;
    }

    //构造方法
    public MovieSystemImpl() {
        readMovies(MOVIE_PATH);
        readUsers(USER_PATH);
        readEvaluates(EVALUATE_PATH);
    }

    //置空方法
    public void clear() {
        //置空
        movieList = null;
        userList = null;
        evaluateList = null;
    }

    //刷新方法
    public void refresh() {
        clear();
        //重新读取
        readMovies(MOVIE_PATH);
        readUsers(USER_PATH);
        readEvaluates(EVALUATE_PATH);
    }

    //读取一行加入电影方法
    private void addMovie(String line) {
        Movie movie = ReaderUtil.readLine2Movie(line);
        movieList.add(movie);
    }
    //读取一行加入用户方法
    private void addUser(String line) {
        User user = ReaderUtil.readLine2User(line);
        userList.add(user);
    }
    //读取一行加入评价方法
    private void addEvaluate(String line) {
        Evaluate evaluate = ReaderUtil.readLine2Evaluate(line);
        evaluateList.add(evaluate);
    }

    @Override
    //读取电影
    public void readMovies(String path) {
        List<Movie> movies = ReaderUtil.readMovie(path);
        if (movies != null) {
            movieList = movies;
        }
    }

    @Override
    //读取用户
    public void readUsers(String path) {
        List<User> users = ReaderUtil.readUser(path);
        if (users != null) {
            userList = users;
        }
    }

    @Override
    //读取评价
    public void readEvaluates(String path) {
        List<Evaluate> evaluates = ReaderUtil.readEvaluate(path);
        if (evaluates != null) {
            evaluateList = evaluates;
        }
    }

    //私有方法:计算当前电影平均分(更新)
    private List<Movie>  refreshMovieAverageScore() {
        //先计算平均分
        //遍历电影集合
        for (Movie movie : movieList) {
            //首先重置平均分和评价人数
            movie.setScore(0);
            movie.setEvaluateCount(0);
        }
        //遍历评价集合
        for (Evaluate evaluate : evaluateList) {
            //获取评价的电影id
            String movieId = evaluate.getMovieId();
            //获取分数
            int score = evaluate.getScore();
            //找到目标电影
            Movie findMovie =null;
            for (Movie movie : movieList) {
                if (movie.getId().equals(movieId)) {
                    findMovie=movie;
                    break;
                }
            }
            //如果没找到
            if (findMovie==null){
                continue;
            }

            //累加平均分和评价人数
            findMovie.setEvaluateCount(findMovie.getEvaluateCount()+1);
            findMovie.setScore(findMovie.getScore()+score);
        }
        //处理完了,计算平均分
        for (Movie movie : movieList) {
            if (movie.getEvaluateCount()>0){
                movie.setAverageScore((double) (movie.getScore()/movie.getEvaluateCount()));
            }else{
                LogCat.e("电影"+movie.getName()+"没有评价");
            }
        }

        //排序(按照平均分从高到低)
        List<Movie> sortedMovies = movieList.stream()
                .sorted(Comparator.comparingDouble(Movie::getAverageScore).reversed())
                .collect(Collectors.toList());
        return sortedMovies;
    }
    @Override
    //获取多少名平均分最高的电影List
    public List<Movie> getTopMovies(int num) {
        List<Movie> movies = refreshMovieAverageScore();
        //取前num个
        //但是要先比较num和数组长度大小
        num = Math.min(num, movies.size());
        return movies.subList(0, num);
    }

    //私有方法,通过id获取电影
    private Movie getMovieById(String movieId) {
        for (Movie movie : movieList) {
            if (movie.getId().equals(movieId)) {
                return movie;
            }
        }
        return null;
    }

    //私有方法,通过id获取用户
    private User getUserById(String userId) {
        //LogCat.d1()
        for (User user : userList) {
            LogCat.d1("集合中id="+user.getId()+"    用户id="+userId);
            //LogCat.printf1(user.getId());
            if ((user.getId()+"").equals(userId)) {
                return user;
            }
            LogCat.d1("本次比较不相同");
        }
        return null;
    }
    //私有方法,通过用户id获取评价集合
    private List<Evaluate> getEvaluatesByUser(String userId) {
        List<Evaluate> evaluates = new ArrayList<>();
        for (Evaluate evaluate : evaluateList) {
            if (evaluate.getUserId().equals(userId)) {
                evaluates.add(evaluate);
            }
        }
        return evaluates;
    }
    @Override
    //获取每位用户评分最高的num个电影
    public Map<User,List<Movie>> getTopMoviesByUser(int num) {

        Map<User,List<Movie>> map = new HashMap<>();

        //遍历评价集合
        for (Evaluate evaluate : evaluateList) {
            //获取评价的用户id
            String userId = evaluate.getUserId();
            //获取评价的电影id
            String movieId = evaluate.getMovieId();

            //获取用户
            User user = getUserById(userId);
            LogCat.d1("user:"+user);
            //如果用户不存在
            if (user == null) {
                continue;
            }
            //查看map中是否有此用户的电影记录
            List<Movie> movies = map.get(user);
            //如果为空
            if (movies == null) {
                movies = new ArrayList<>();
            }
            //获取电影
            Movie movie = getMovieById(movieId);
            //如果电影不存在
            if (movie == null) {
                continue;
            }
            //添加到集合中
            movies.add(movie);

            //更新map
            map.put(user,movies);
        }

        //打印日志测试一下
        LogCat.d1("map集合:"+map);
        //现在map集合已经有了,知道了什么用户评价了什么电影
        //需要对所有的电影进行排序
        for (User user : map.keySet()) {

            //获取用户的所有电影
            List<Movie> movies = map.get(user);
            //获取用户所有评价
            List<Evaluate> evaluates = getEvaluatesByUser(user.getId()+"");
            //遍历,如果评价电影id正好等于用户所有电影id
            for (Evaluate evaluate : evaluates) {
                //获取评价的电影id
                String movieId = evaluate.getMovieId();
                //遍历用户的所有电影
                for (Movie movie : movies) {
                    //如果电影id相等
                    if (movie.getId().equals(movieId)) {
                        //设置电影的评分
                        movie.setTempScore(evaluate.getScore());
                        break;
                    }
                }
            }
            //现在电影都有评分了
            //排序(按照评分从高到低)
            movies.sort(Comparator.comparingDouble(Movie::getTempScore).reversed());
            //取前num个
            //但是要先比较num和数组长度大小
            num = Math.min(num, movies.size());
            LogCat.d1("num:"+num);
            // 更新movies列表以只包含前num个元素
            movies = new ArrayList<>(movies.subList(0, num));
            //还要放回去
            map.put(user,movies);
            //打印一下现在的长度
            LogCat.d1("现在的长度:"+movies.size());
        }


        return map;
    }

    @Override
    //评论最多的多少部电影
    public List<Movie> getTopMoviesByEvaluate(int num) {

        //清空电影评价
        for (Movie movie : movieList) {
            movie.setEvaluateCount(0);
        }
        //遍历评价集合
        for (Evaluate evaluate : evaluateList) {
            //获取评价的电影id
            String movieId = evaluate.getMovieId();
            //找到对应电影
            Movie movie = getMovieById(movieId);
            //设置评价数量
            movie.setEvaluateCount(movie.getEvaluateCount()+1);
        }

        //排序
        movieList.sort(Comparator.comparingInt(Movie::getEvaluateCount).reversed());
        //取前num个
        num = Math.min(num, movieList.size());
        return movieList.subList(0, num);
    }

    @Override
    //评分最多的num部电影,并给出评分次数
    public Map<Movie, Integer> getTopMoviesByScore(int num) {
        //直接调用上面的方法
        List<Movie> topMoviesByEvaluate = getTopMoviesByEvaluate(num);
        Map<Movie, Integer> map = new HashMap<>();
        for (Movie movie : topMoviesByEvaluate) {
            map.put(movie,movie.getEvaluateCount());
        }
        return map;
    }

    @Override
    //获取前几名电影评分(以平均分为标准)
    public List<Movie> getTopEvaluates(int num) {
        //更新计算平均分
        List<Movie> movies = refreshMovieAverageScore();
        //排序
        movies.sort(Comparator.comparingDouble(Movie::getAverageScore).reversed());
        //计算数量
        num = Math.min(num, movies.size());
        //返回
        return movies.subList(0, num);

    }

    @Override
    //求year年中的电影,评分最高的num部type类型电影
    public List<Movie> getTopMoviesByYear(int year, int num, String type) {
        //遍历原有电影列表
        List<Movie> movies = new ArrayList<>();
        for (Movie movie : movieList) {
            //判断年份和类型是否相等
            if (movie.getReleaseTime().getYear() == year&& movie.getType().equals(type)) {
                movies.add(movie);
            }
        }
        //排序
        movies.sort(Comparator.comparingDouble(Movie::getAverageScore).reversed());
        //取前num个
        num = Math.min(num, movies.size());
        return movies.subList(0, num);

    }

    //私有方法:计算当前电影平均分(更新)带上性别要求
    private List<Movie>  refreshMovieAverageScore(boolean isBoy) {
        //先计算平均分
        //遍历电影集合
        for (Movie movie : movieList) {
            //首先重置平均分和评价人数
            movie.setScore(0);
            movie.setEvaluateCount(0);
        }
        //遍历评价集合
        for (Evaluate evaluate : evaluateList) {
            //获取评价者
            User user = getUserById(evaluate.getUserId());
            //判断性别
            //如果需要男生
            if (isBoy){
                if(!user.getSex().equals("男")){
                    continue;
                }
            }else {
                if(user.getSex().equals("男")){
                    continue;
                }
            }
            //获取评价的电影id
            String movieId = evaluate.getMovieId();
            //获取分数
            int score = evaluate.getScore();
            //找到目标电影
            Movie findMovie =null;
            for (Movie movie : movieList) {
                if (movie.getId().equals(movieId)) {
                    findMovie=movie;
                    break;
                }
            }
            //如果没找到
            if (findMovie==null){
                continue;
            }

            //累加平均分和评价人数
            findMovie.setEvaluateCount(findMovie.getEvaluateCount()+1);
            findMovie.setScore(findMovie.getScore()+score);
        }
        //处理完了,计算平均分
        for (Movie movie : movieList) {
            if (movie.getEvaluateCount()>0){
                movie.setAverageScore((double) (movie.getScore()/movie.getEvaluateCount()));
            }else{
                LogCat.e("电影"+movie.getName()+"没有评价");
            }
        }

        //排序(按照平均分从高到低)
        List<Movie> sortedMovies = movieList.stream()
                .sorted(Comparator.comparingDouble(Movie::getAverageScore).reversed())
                .collect(Collectors.toList());
        return sortedMovies;
    }

    @Override
    //求男性或女性中评分最高的num部电影(依然把评分认为是平均分)
    public List<Movie> getTopMoviesBySex(int num, String sex) {
        //直接调用上面的方法
        if("男".equals(sex)){
            List<Movie> movies = refreshMovieAverageScore(true);
            LogCat.d3(movies.toString());
            return movies.subList(0, num);
        }
        if("女".equals(sex)){
            List<Movie> movies = refreshMovieAverageScore(false);
            LogCat.d3(movies.toString());
            return movies.subList(0, num);
        }
        return List.of();
    }

    public void test(){
        LogCat.d1("test");
        for (Movie movie : movieList) {
            LogCat.d1(movie.toString());
        }
        LogCat.d1("------------------");
        for (User user : userList) {
            LogCat.d1(user.toString());
        }
        LogCat.d1("------------------");
        for (Evaluate evaluate : evaluateList) {
            LogCat.d1(evaluate.toString());
        }

    }

}
